package tech.anzhen.simple.rpc.support.runtime;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

public class ModuleErrorCode {

    private static Map<Class<?>, Resolved> cache = new HashMap<Class<?>, Resolved>();

    public static String getModuleCode(Class<?> enumClass) {
        return get(enumClass).moduleCode;
    }

    public static String getModuleErrorCode(Enum<?> code) {

        Class<?> clazz = code.getClass();
        Resolved resolved = get(clazz);

        String value = (String) resolved.codes.get(code);
        if (value == null) {
            throw new IllegalArgumentException();
        }
        return resolved.moduleCode + value;
    }

    private synchronized static Resolved get(Class<?> enumClass) {
        Resolved resolved = cache.get(enumClass);
        if (resolved == null) {
            resolved = load(enumClass);
            cache.put(enumClass, resolved);
        }
        return resolved;
    }

    private static Resolved load(Class<?> enumClass) {

        Module module = enumClass.getAnnotation(Module.class);
        if (module == null) {
            throw new IllegalArgumentException(enumClass + "没有@Module注解");
        }

        Resolved r = new Resolved();
        r.moduleCode = module.moduleCode();
        r.codes = new HashMap<Object, Object>();

        try {
            for (Field field : enumClass.getDeclaredFields()) {
                int m = field.getModifiers();
                if (!field.getType().equals(enumClass)) {
                    continue;
                }
                if (Modifier.isPublic(m) && Modifier.isStatic(m) && Modifier.isFinal(m)) {
                    Object enumValue = field.get(null);
                    Code code = field.getAnnotation(Code.class);
                    if (code == null) {
                        throw new IllegalArgumentException(field + "没有@Code注解");
                    }

                    r.codes.put(enumValue, code.value());
                    r.codes.put(code.value(), enumValue);
                }
            }
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException(e);
        }
        return r;
    }

    static class Resolved {

        private String moduleCode;

        private Map<Object, Object> codes;
    }

    public static void main(String[] args) {
        String s = getModuleErrorCode(T.ERROR);
        s = getModuleErrorCode(T.ERROR);
        s = getModuleErrorCode(T.ERROR);
        System.out.println(s);
    }

    @Module(moduleCode = "0001")
    static enum T {

        @Code("0001")
        ERROR
    }

}
